﻿using System;
using SimpleServiceBus.Bus.MessageManagement.MessageHandling;
using SimpleServiceBus.Bus.Pipeline;
using SimpleServiceBus.Utilities;
using System.Globalization;
using System.Xml;
using System.Linq;

namespace SimpleServiceBus.Bus.MessageManagement.MessageHandling
{
    public class DefaultMessageDispatcher : IMessageDispatcher
    {
        #region IMessageDispatcher Members

        public void Dispatch(MessageEnvelope messageEnvelope, IMessageContext messageContext)
        {
            var unitOfWorkFactory = messageContext.GetLocalService<IUnitOfWorkFactoryService>();
            IDisposable work = null;
            if (unitOfWorkFactory != null)
                work = unitOfWorkFactory.CreateUnitOfWork();

            try
            {
                var resolutionService = messageContext.GetLocalService<IMessageHandlerResolutionService>();

                if (resolutionService != null)
                {
                    IMessageHandler[] handlers = resolutionService.ResolveHandlersFor(messageEnvelope);
                    if(handlers != null && handlers.Length > 0) {
                        foreach(IMessageHandler handler in handlers) {
                            handler.Handle(messageEnvelope.Body, messageContext);
                            if (messageContext.AbortMessageProcessing)
                                return;
                        }
                    }
                    else {
                        String _messageTypeName = "";
                        if(messageEnvelope.Body != null) {
                            var _xmlNodes = messageEnvelope.Body as XmlNode[];
                            if(_xmlNodes != null) {
                                var _typeAttribute = _xmlNodes.FirstOrDefault(x => x.Name == "xsi:type");
                                if(_typeAttribute != null)
                                    _messageTypeName = _typeAttribute.Value;
                            }
                            else 
                                _messageTypeName = messageEnvelope.Body.GetType().FullName;
                        }
                        throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Could not find a handler for message id={0}, type={1}, retryCount={2}, returnAddress={3}, correlationID={4}", 
                            messageEnvelope.MessageID, _messageTypeName, messageEnvelope.RetryCount, messageEnvelope.ReturnAddress, messageEnvelope.CorrelationID));
                    }
                }
            }
            finally
            {
                if (work != null)
                    work.Dispose();
            }
        }

        #endregion
    }
}